//
// Created by LiuYou on 2021/6/27.
//

#include <cstdlib>
#include <pthread.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <memory>


#define THR_NUM         4


//static pthread_mutex_t mutex[THR_NUM];
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static int num;

static int next(int n) {
    if (n + 1 == THR_NUM) {
        return 0;
    }
    return n + 1;
}

static void* thr_func(void* pVoid) {
    int c = 'a' + *((int*) pVoid);
    int n = *((int*) pVoid);
    delete (int*) pVoid;

    while (true) {
//        pthread_mutex_lock(mutex + n);
        pthread_mutex_lock(&mutex);
        while (num != n) {
            pthread_cond_wait(&cond, &mutex);
        }
        write(1, &c, 1);
        num = next(num);
        pthread_cond_broadcast(&cond);

        // TODO 注意: 这里不能直接加以1, 而是要取模。所以提取为一个函数是一个更好的做法。
//        pthread_mutex_unlock(mutex + n + 1);
//        pthread_mutex_unlock(mutex + next(n));
        pthread_mutex_unlock(&mutex);
    }

    pthread_exit(nullptr);
}

/**
 * @brief abcdabcdabcdabcdabcdabcdabcd......
 *
 *        15版本是对之前的abcdabcdabcd...顺序打印的改进版。
 */
int main() {


    pthread_t tid[THR_NUM]{};

    // main线程创建了这么多线程。
    for (int i = 0; i < THR_NUM; ++i) {

//        pthread_mutex_init(mutex + i, nullptr);
//        pthread_mutex_lock(mutex + i);



        // TODO 注意: 在 C++中这里是有段错误的。
        //  通过调试将错误锁定在了这个强转这里。
        //  原因: C++不允许这样的强转。而 C是允许的。

        int* pInt = new int(i);

        int err = pthread_create(tid + i, nullptr, thr_func, pInt);
//        int err = pthread_create(tid + i, nullptr, thr_func, static_cast<void*>(i));
//        int err = pthread_create(tid + i, nullptr, thr_func, (void*) i);
        if (err) {
            std::fprintf(stderr, "pthread_create(): %s\n", std::strerror(err));
            std::exit(EXIT_FAILURE);
        }
    }

//    pthread_mutex_unlock(mutex + 0);

    alarm(5);


    // main线程对创建的线程进行收尸。
    for (int i = 0; i < THR_NUM; ++i) {
        pthread_join(tid[i], nullptr);
    }


    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);


    std::exit(EXIT_SUCCESS);
}